import { loadGltf } from '../utils/loader';
import { camera, init, renderer, scene, light, ground, stats, width, height } from './scene';
import { Line2 } from "three/examples/jsm/lines/Line2.js";
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry.js";

import * as THREE from 'three'
import { castShadow } from '../utils/shadow';

import TWEEN, { Tween } from '@tweenjs/tween.js'
import { IntervalTime, unreal } from '../utils';
import { ResourceTracker } from '../utils/ResourceTracker';


init();

const params = {
    threshold: 0.349,
    strength: 0.567, // 强度
    radius: 0,// 半径
    exposure: 1.55 // 扩散
};

// 获取发光场景必要元素
const { finalComposer: F,
    bloomComposer: B,
    renderScene: R, bloomPass: BP } = unreal(scene, camera, renderer, width, height, params)
let finalComposer = F
let bloomComposer = B
let renderScene = R
let bloomPass = BP

bloomPass.threshold = 0

const bloomLayer = new THREE.Layers();
const BLOOM_SCENE = 1;
bloomLayer.set(BLOOM_SCENE);

const materials: any = {}

const darkMaterial = new THREE.MeshBasicMaterial({ color: 'black' });

let intervalTime: IntervalTime | null = new IntervalTime()

const wavyLineGroup = new THREE.Group()
// 其他车辆模型
let otherCarModel: THREE.Object3D
const otherCarGroup = new THREE.Group();

let ZP = [-1.8, -3.8, 4.4, 6.3, 8.2]

// materials 
// 雷达扇形材质
const radarMaterial = new THREE.MeshBasicMaterial({
    color: 0xffffff,
    transparent: true,
    opacity: 0.1,
});


// 线的材质
const radarLine2MatLine = new LineMaterial({
    linewidth: 0.004, // 可以调整线宽
    color: 0xffffff,
    vertexColors: false, // 是否使用顶点颜色
    fog: true
});

const createNewOtherCar = () => {
    const OC = otherCarModel.clone();
    const z = ZP[getRandomIntegerInRange(0, ZP.length - 1)]
    let x = 0
    if (z <= 0) {
        x = 25
        OC.rotation.set(0, Math.PI * 1.5, 0)
    } else {
        x = -70
    }

    // 随机分布
    OC.position.copy(new THREE.Vector3(x, 0.01, z))
    yoyoTween(OC)


}

let maxCount = 20
let intervalCount = 0
const render = () => {
    TWEEN && TWEEN.update();
    renderer.render(scene, camera);
    stats.update()

    if (bloomComposer) {
        scene.traverse(darkenNonBloomed.bind(this));
        bloomComposer.render();
    }
    if (finalComposer) {
        scene.traverse(restoreMaterial.bind(this));
        finalComposer.render();
    }

    if (maxCount > intervalCount) {
        intervalTime?.interval(() => {
            createNewOtherCar()
            intervalCount++
        }, 1000)
    } else {
        intervalTime = null
    }

    line2Group.traverse((line2: any) => {
        if (line2.isLine2) {
            line2 as Line2
            const geo = line2.geometry;
            const positions = geo.getAttribute('position');
            const { array, count } = positions
            for (let i = 0; i < count; i++) {
                const v3 = new THREE.Vector3().fromArray(array, i);
                
            }
        }
    })
}


function darkenNonBloomed(obj: THREE.Mesh) {
    if (bloomLayer) {
        if (!obj.userData.isLight && bloomLayer.test(obj.layers) === false) {
            materials[obj.uuid] = obj.material;
            obj.material = darkMaterial;
        }
    }

}

function restoreMaterial(obj: THREE.Mesh) {
    if (materials[obj.uuid]) {
        obj.material = materials[obj.uuid];
        // 用于删除没必要的渲染
        delete materials[obj.uuid];
    }
}

const playerGroup = new THREE.Group();
let model

const loadPlayer = async () => {
    await loadOtherCar()
    const gltf = await loadGltf(`${import.meta.env.VITE_ASSETS_URL}assets/models/car/scene.gltf`);
    model = gltf.scene;
    const playerScale = 0.5

    model.scale.set(playerScale, playerScale, playerScale)

    playerGroup.add(model)



    castShadow(model)

    playerGroup.rotation.set(0, Math.PI, 0)
    playerGroup.position.set(0, 0, 0);

    scene.add(playerGroup);
    scene.add(otherCarGroup);

    // await renderer.compileAsync(model, camera, scene);
    renderer.setAnimationLoop(render);
    light.position.copy(camera.position.clone().negate().setY(camera.position.y))

    scene.add(wavyLineGroup);

    loopGround()

}


window.onload = () => {
    loadPlayer()
}

const carMaterial2Wite = (model: THREE.Object3D) => {
    model.traverse((mesh: THREE.Object3D<THREE.Object3DEventMap>) => {
        mesh.castShadow = true;
        if (mesh.material) {
            mesh.material = new THREE.MeshLambertMaterial({
                color: 0xffffff
            })
        }
    })
}


/**
 * 
 * @param radius 半径
 * @param thetaLength 中心角
 * @param index 索引，防止粘黏
 * @param type 动画类型
 */
const line2Group = new THREE.Group();
playerGroup.add(line2Group)
let tweens: Tween<Record<string, any>>[] = []
const createRadar = (radius: number, thetaLength: number, index?: number, type?: "radius" | "thetaLength") => {
    // 初始化数据
    const InitialThetaLength = Math.PI * 0.01;
    const InitialRadiue = 0.001;

    // 创建圆弧信息
    const geometry = new THREE.CircleGeometry(InitialRadiue, 361, -InitialThetaLength / 2, InitialThetaLength)

    // 创建扇形几何体
    const circle = new THREE.Mesh(geometry, radarMaterial);

    circle.rotation.set(-Math.PI * 0.5, 0, 0);

    // 获取扇形几何体的顶点信息
    const linePoints = geometryAttribute2Array(geometry)
    // 创建线
    const line2Geometry = new LineGeometry();

    // 设置line2的顶点信息
    line2Geometry.setPositions(linePoints);

    let line2 = new Line2(line2Geometry, radarLine2MatLine);
    circle.position.y = 0.001 * (index || 0)
    line2Group.add(line2)
    line2.userData.isLight = true
    playerGroup.add(circle)

    // 动态计算时间，让动画有点层次感
    const tweenTime = (type === 'radius' ? 2 : thetaLength) * 1000;
    // 初始值为半径和中心角的初始化值
    let tween = new TWEEN.Tween({ radius: InitialRadiue, thetaLength: InitialThetaLength })
        .to({ radius, thetaLength }, tweenTime) // 目标值为方法的实参radius和thetaLength
        .onUpdate(({ radius: r, thetaLength: t }) => {
            let newGeometry: THREE.CircleGeometry
            if (type === 'radius') {
                // 只对半径做修改
                newGeometry = new THREE.CircleGeometry(r, 361, -thetaLength / 2, thetaLength);
            } else if (type === 'thetaLength') {
                // 只对中心角做修改
                newGeometry = new THREE.CircleGeometry(radius, 361, -t / 2, t);
            } else {
                // 同时修改
                newGeometry = new THREE.CircleGeometry(r, 361, -t / 2, t);
            }

            // 更新雷达扇形
            circle.geometry.setAttribute('position', newGeometry.getAttribute('position'))

            // 更新扇形外围弧线顶点信息
            const linePoints = geometryAttribute2Array(newGeometry)
            line2Geometry.setPositions(linePoints);
        })
    tweens.push(tween)

}


document.querySelector('button')?.addEventListener('click', () => {
    createRadar(40, Math.PI * 0.04, 1)
    createRadar(15, Math.PI * 0.4, 2, 'thetaLength')
    createRadar(6, Math.PI * 2, 3, 'radius')

    tweens.forEach((tween) => {
        tween.start()
    })
})


// 将BufferGeometry的顶点信息转成数组
const geometryAttribute2Array = (geometry: THREE.BufferGeometry): Array<number> => {
    let linePoints = []
    if (geometry.isBufferGeometry) {
        const position = geometry.getAttribute('position')
        const { count } = position
        // 循环几何体的顶点信息并加入到linePoints中。
        for (let i = 1; i < count; i++) {
            const v3 = new THREE.Vector3().fromBufferAttribute(position, i);
            linePoints.push(v3.x, v3.z, v3.y)
        }
    }
    return linePoints
}

const loadOtherCar = async () => {
    const gltf = await loadGltf(`${import.meta.env.VITE_ASSETS_URL}assets/models/low_poly_small_car/scene.gltf`);
    otherCarModel = gltf.scene;
    const otherModelScalse = 0.2
    otherCarModel.rotation.set(0, Math.PI * 0.5, 0)
    otherCarModel.scale.set(otherModelScalse, otherModelScalse, otherModelScalse);

    carMaterial2Wite(otherCarModel);
}

// 获取两点之间的随机整数
function getRandomIntegerInRange(min: number, max: number): number {
    // 确保 min 是最小值，max 是最大值
    if (min > max) {
        const temp = min;
        min = max;
        max = temp;
    }
    // 返回 min 和 max 之间的随机整数
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

// 其他车辆自主往复运动
const yoyoTween = (mesh: THREE.Object3D) => {
    // 删除模型的类
    let startX = mesh.position.clone().x;
    let offset = 120
    let x = startX < 0 ? startX + offset : startX - offset

    const resMgr = new ResourceTracker();
    const track = resMgr.track.bind(resMgr)

    const mesTrack = track(mesh)
    otherCarGroup.add(mesTrack)

    const box3 = new THREE.Box3();
    box3.setFromObject(mesh)
    new TWEEN.Tween(mesh.position)
        .to(mesh.position.clone().setX(x), startX < 0 ? 4000 : 12000) // 目标值为方法的实参radius和thetaLength
        .start()
        .repeat(Infinity)
}

// 背景图偏移效果
const loopGround = () => {
    new TWEEN.Tween({ offsetX: 0.12 })
        .to({ offsetX: 1.12 }, 6000) // 目标值为方法的实参radius和thetaLength
        .start()
        .repeat(Infinity)
        .onUpdate(({ offsetX }) => {
            ground.material.map.offset.set(0, offsetX); // 这里的值可以根据你需要的偏移来调整
        })
}

